#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <tr.h>

/* for ASCII character set only */
#define ASCII_CHARSET_SIZE 0x80

int main(int argc, char ** argv, char ** envp)
{
    int i, j;
    int res;
    char * s1, * s2;
    unsigned char charset[ASCII_CHARSET_SIZE];

    if (argc < 3) {
	fprintf(stderr, "Usage: tr string1 string2\n");
	return -1;
    }

    for (i = 0; i < ASCII_CHARSET_SIZE; i++) {
	charset[i] = i;
    }

    s1 = argv[1]; s2 = argv[2];
    for (i = 0, j = 0; i < strlen(s1); i++) {
	charset[(int)s1[i]] = s2[j];
	j = (j >= strlen(s2)-1) ? strlen(s2)-1 : j+1;
    }

    if (0 != (res = tr(charset, ASCII_CHARSET_SIZE))) {
	//fprintf(stderr, "error: tr\n");
	printf(_strerror("tr failed"));
	return -1;
    }

    return 0;
}

/*
 * tr - a simple implementation of command tr
 *
 * return 0 for success, otherwise -1 and set errno
 *
 */
int tr(const char * charset, const int charset_size)
{
    int c;

    if (!charset || charset_size <= 0) {
	errno = EINVAL;
	return -1;
    }

    do {
	c = getc(stdin);
	if (c == EOF) {
	    if (ferror(stdin)) {
	    perror("getc() failed");
	    return -1;
	    }
	    if (feof(stdin))
		return 0;	/* EOF encountered */
	    assert(0);
	} 
	if (c > charset_size) {
	    fprintf(stderr, "%s:%d: getc()'s return: out of character range\n", __FILE__, __LINE__);
	    errno = ERANGE;
	    return -1;
	}
	c = putc(charset[c], stdout);
	if (c == EOF) {
	    if (ferror(stdout)) {
		fprintf(stderr, "%s:%d: putc() failed: %s\n", __FILE__, __LINE__, strerror(errno));
		return -1;
	    }
	    if (feof(stdout)) {
		return 0;
	    }
	    assert(0);
	}
    } while (1);

    assert(0);
}

/*
 * learned: 
 * 1) getc() and putc() return EOF standing for EOF or error. use ferror() or feof() to tell which.
 * 2) perror, strerror(errno), _strerror are better ways to print out error messages.
 *
 */
